package com.zookeeper;

import com.common.dict.Constant2;
import com.common.util.SystemHWUtil;
import com.google.common.eventbus.EventBus;
import com.string.widget.util.ValueWidget;
import com.swing.messagebox.GUIUtil23;
import com.zookeeper.event.ZkModifyEvent;
import org.apache.log4j.Logger;
import org.apache.zookeeper.*;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.CountDownLatch;

public class ZkConnect {
    protected static final Logger logger = Logger.getLogger(ZkConnect.class);
    private ZooKeeper zk;
    private CountDownLatch connSignal = new CountDownLatch(0);
    private static EventBus eventBus = new EventBus();
    /***
     * 搜索缓存<br />
     * key 是搜索路径,即 方法zkConnect.search 的第一个参数
     */
    private static Map<String, Map<String, String>> searchResultCacheMap = new HashMap<>();

    /***
     * zk 的目录
     */
    public static String rootPath = "/demo/1.0.0/constant/";

    public static Map<String, Map<String, String>> getSearchResultCacheMap() {
        return searchResultCacheMap;
    }

    public byte[] getData(String zNodePath) throws KeeperException, InterruptedException {
        byte[] data = zk.getData(zNodePath, true, zk.exists(zNodePath, true));
        return data;
    }

    public boolean isEmptyDirectory(String zNodePath) {
        return false;//TODO 待实现
    }

    /***
     * 清空缓存
     */
    public static void clearCache() {
        searchResultCacheMap.clear();
        if (0 != searchResultCacheMap.size()) {
            searchResultCacheMap = new HashMap<>();
        }
    }


    /***
     * 只清除一条记录
     * @param path
     */
    public static void clearCache(String path) {
        if (searchResultCacheMap.size() > 0) {
            searchResultCacheMap.remove(path.replace("/", ""));
        }
    }

    public static Map<String, String> search(String path, ZooKeeper zk) throws KeeperException, InterruptedException {
        String key = path.replace("/", "_");
        if (searchResultCacheMap.containsKey(key)) {
            System.out.println("使用缓存 :" + path);
            return searchResultCacheMap.get(key);
        }
        if (null == zk) {
            GUIUtil23.warningDialog("zk 未连接上");
            return null;
        }
        //最开始,path是"/"
        if (!Constant2.SLASH.equals(path)) {
            path = path.replaceAll("/$", SystemHWUtil.EMPTY);
        }
        List<String> zNodes = zk.getChildren(path, true);
        if (zNodes.size() == 0) {
            return null;
        }
        Map<String, String> map = new TreeMap<>();
        if (Constant2.SLASH.equals(path)) {
            path = "";
        }
        for (String zNode : zNodes) {
//            System.out.println("ChildrenNode " + zNode);
            String zNodePath = path + "/" + zNode;
            String val = getNodeValue(zk, zNodePath);
            map.put(zNode, val);
        }
        if (map.size() > 0 && key.length() > 1) {
            searchResultCacheMap.put(key, map);
        }
        return map;
    }

    public static String getNodeValue(ZooKeeper zk, String zNodePath) throws KeeperException, InterruptedException {
        byte[] data = zk.getData(zNodePath, true, zk.exists(zNodePath, true));
        if (data == null) {
            System.out.println("zNodePath :" + zNodePath);
            return "无数据";
        }
        String val = null;
        try {
            val = new String(data, SystemHWUtil.CHARSET_UTF);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return val;
    }

    /*public static ZkConnect connect() throws Exception {
        ZkConnect connector = new ZkConnect();//
        *//*ZooKeeper zk = *//*
        connector.connect(, null);
//        connector.zk=zk;
        return connector;
    }*/

    //host should be 127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002
    public ZooKeeper connect(String host, Integer port) throws Exception {

        if (null == port) {
            port = 2181;
        }
        host = host.replaceAll("[\\s]*:[\\s]*[0-9]+", "");
        String hostLog = "zk server:" + host;
        String portLog = "zk port:" + port;
        logger.warn(hostLog);
        logger.warn(portLog);
        System.out.println(hostLog);
        System.out.println(portLog);
        zk = new ZooKeeper(host, port, (event) -> {
            if (event.getState() == KeeperState.SyncConnected) {
                connSignal.countDown();
            }
        });
        connSignal.await();
        return zk;
    }

    public void close() throws InterruptedException {
        zk.close();
    }

    public void createNode(String path, byte[] data) throws Exception {
        zk.create(path, data, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
    }

    public void createNode(String path, String data) throws Exception {
        createNode(path, data.getBytes(SystemHWUtil.CHARSET_UTF));
    }

    public void createNode(String path) throws Exception {
        createNode(path, new Date().toString().getBytes());
    }

    public void updateNode(String path, byte[] data) throws Exception {
        zk.setData(path, data, zk.exists(path, true).getVersion());
    }

    public String updateNode(String path, String data) throws Exception {
        byte[] val = zk.getData(path, true, zk.exists(path, true));

        String oldVal = null;
        if (!ValueWidget.isNullOrEmpty(val)) {
            oldVal = new String(val, SystemHWUtil.CHARSET_UTF);
            logger(path, oldVal);
            System.out.println("原值:" + oldVal);
        }
        updateNode(path, data.getBytes(SystemHWUtil.CHARSET_UTF));
        return oldVal;
    }

    public void deleteNode(String path) throws Exception {
        String val = getNodeValue(zk, path);
        zk.delete(path, zk.exists(path, true).getVersion());
        logger(path, val);
    }

    public static void logger(String path, String val) {
        System.out.println("更新 ,val:" + val + ", path:" + path);
        ZkModifyEvent zkModifyEvent = new ZkModifyEvent(path, val);
        eventBus.post(zkModifyEvent);
    }

    public ZooKeeper getZk() {
        return zk;
    }

    public static EventBus getEventBus() {
        return eventBus;
    }
}
